/**
 * 
 */

package com.wutianyi.maven.packet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.wutianyi.maven.constants.ModeEnum;
import com.wutianyi.maven.constants.ResourceLoadType;
import com.wutianyi.maven.properties.ConfigProperties;
import com.wutianyi.maven.vm.TemplateWrap;
import com.wutianyi.maven.xml.ParserXmlDom4j;

/**
 * @author wutianyi
 * 
 */
public class UnWar {

	private Logger logger = Logger.getLogger(UnWar.class);

	/**
	 *需要处理的war包 ,jar包也可以
	 */
	private String warPath;
	
	private String mode;
	
	private ConfigProperties properties;

	private static final String TEMP_DIRECTORY = "target/temp";
	
	private static final String JAR_AUTOCONFIG_PAT = "META-INF/autoconfig.xml";

	private static final String TEMP_LIB_DIRECTORY = "target/temp/jar/";

	private static final String AUTOCONFIG_PATH = "target/temp/WEB-INF/classes/META-INF/autoconfig.xml";

	private static final String VM_DIRECTORY = "target/temp/WEB-INF/classes/META-INF";

	private static final String VM_OUTPUT_DIRECTORY = "target/temp/WEB-INF/classes";

	private static final String LIB_PATH = "target/temp/WEB-INF/lib";

	public UnWar(String warPath, String configPropertiesPath, String mode) {

		this.warPath = warPath;
		this.mode = mode;
		if (StringUtils.isNotBlank(configPropertiesPath)) {
			properties = new ConfigProperties(configPropertiesPath);
		} else {
			properties = new ConfigProperties();
		}

	}

	public void close() {
		try {
			FileUtils.deleteDirectory(new File(TEMP_DIRECTORY));
			
			properties.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void unWar() {

		try {
			unWarDetail();
			autoconfigWar();
			logger.info("[Begin Autoconfig Jar]");
			File file = new File(LIB_PATH);
			File[] files = file.listFiles();

			if (null != files) {
				for (File f : files) {
					String name = f.getName();
					if (unJar(f, name)) {
						logger.info("[AutoConfig]: " + name);
						autoconfigJar(name);
						jarFile(LIB_PATH, TEMP_LIB_DIRECTORY + name, name);
						logger.info("[Finisht AutoConfig]: " + name);
						FileUtils.deleteDirectory(new File(TEMP_LIB_DIRECTORY
								+ name));
					}
				}
			}
			FileUtils.deleteDirectory(new File(TEMP_LIB_DIRECTORY));
			logger.info("[Finish Autoconfig Jar]");
			jarFile("target", TEMP_DIRECTORY, new File(warPath).getName());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void jarFile(String outputPath, String sourcePath, String name)
			throws FileNotFoundException, IOException {
		JarOutputStream outputStream = new JarOutputStream(
				new FileOutputStream(new File(outputPath, name)));
		File unJarFile = new File(sourcePath);
		File[] files = unJarFile.listFiles();

		if (null != files) {
			for (File file : files) {
				jarFileDetail(outputStream, file, "");
			}
		}
		outputStream.flush();
		outputStream.close();
	}

	private void jarFileDetail(JarOutputStream outputStream, File f, String base)
			throws IOException {
		if (f.isDirectory()) {
			outputStream.putNextEntry(new JarEntry(base + f.getName() + "/"));
			File[] files = f.listFiles();
			if (null != files) {
				for (File file : files) {
					jarFileDetail(outputStream, file, base + f.getName() + "/");
				}
			}

		} else {
			outputStream.putNextEntry(new JarEntry(base + f.getName()));
			InputStream inputStream = null;
			try {
				inputStream = new FileInputStream(f);
				byte[] buffer = new byte[1024];
				int len = 0;
				while ((len = inputStream.read(buffer)) != -1) {
					outputStream.write(buffer, 0, len);
				}
			} finally {
				inputStream.close();
			}
			outputStream.closeEntry();
		}
	}

	/**
	 * 解压war包
	 * 
	 * @throws IOException
	 */
	private void unWarDetail() throws IOException {
		JarFile warFile = new JarFile(new File(warPath));
		Enumeration<JarEntry> jarEntrys = warFile.entries();

		while (jarEntrys.hasMoreElements()) {
			handleJarEntry(TEMP_DIRECTORY, warFile, jarEntrys.nextElement());
		}
	}

	/**
	 * 自动配置war中定义的vm
	 */
	private void autoconfigWar() {
		File file = new File(AUTOCONFIG_PATH);
		
		if(!file.exists()) {
			return;
		}
		
		ParserXmlDom4j config = new ParserXmlDom4j(AUTOCONFIG_PATH, true);

		TemplateWrap templateWrap = new TemplateWrap(config, properties,
				ResourceLoadType.FILE.getType(), VM_DIRECTORY, mode);
		templateWrap.mergeTemplate(VM_OUTPUT_DIRECTORY);
	}

	/**
	 * 解压依赖到的jar包
	 * 
	 * @throws IOException
	 */
	private boolean unJar(File f, String name) throws IOException {
		JarFile jarFile = new JarFile(f);

		JarEntry entry = jarFile.getJarEntry(JAR_AUTOCONFIG_PAT);
		// 如果没有指定的autoconfig文件，则就不进行解压
		if (null == entry) {
			jarFile.close();
			return false;
		}

		Enumeration<JarEntry> entrys = jarFile.entries();

		while (entrys.hasMoreElements()) {

			handleJarEntry(TEMP_LIB_DIRECTORY + name, jarFile, entrys
					.nextElement());

		}
		jarFile.close();
		return true;
	}

	/**
	 * 更新jar文件中的vm模板
	 */
	private void autoconfigJar(String name) {
		ParserXmlDom4j config = new ParserXmlDom4j(TEMP_LIB_DIRECTORY + name
				+ "/META-INF/autoconfig.xml", true);

		TemplateWrap templateWrap = new TemplateWrap(config, properties,
				ResourceLoadType.FILE.getType(), TEMP_LIB_DIRECTORY + name
						+ "/META-INF", ModeEnum.DEV.getValue());
		templateWrap.mergeTemplate(TEMP_LIB_DIRECTORY + name);
	}

	/**
	 * 处理每个entry，具体为解压缩
	 * 
	 * @param parent
	 * @param jarFile
	 * @param jarEntry
	 */
	private void handleJarEntry(String parent, JarFile jarFile,
			JarEntry jarEntry) {

		if (jarEntry.isDirectory()) {
			File file = new File(parent, jarEntry.getName());
			boolean result = file.mkdirs();
			if (result) {
				logger.info("[Make The Directory: ]" + file.getAbsolutePath());
			}
		} else {
			File file = new File(parent, jarEntry.getName());
			if(!file.getParentFile().exists()) {
				boolean result = file.getParentFile().mkdirs();
				if(result) {
					logger.info("[Make Directory]: " + file.getParent());
				}
			}
			FileOutputStream outputStream = null;
			InputStream inputStream = null;
			try {
				outputStream = new FileOutputStream(file);
				inputStream = jarFile.getInputStream(jarEntry);
				byte[] buffer = new byte[1024];
				int len = 0;
				while ((len = inputStream.read(buffer)) != -1) {
					outputStream.write(buffer, 0, len);
				}
				outputStream.flush();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if(null != outputStream) {
						
						outputStream.close();
					}
					if(null != inputStream) {
						inputStream.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static void main(String[] args) throws IOException {
		UnWar war = new UnWar("wutianyi86728_8.war", "", "develop");
		war.unWar();
		war.close();
//		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
//		String value = reader.readLine();
//		System.out.println(value);
	}
}
